﻿using Quartz;
using Quartz.Impl;
using Quartz.Impl.Matchers;
using Quartz.Impl.Triggers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TXTD.Admin.Data.Entitys.System;
using TXTD.Admin.Framework.CostomException;
using TXTD.Admin.Interface.System;
using TXTD.Admin.ScheduledTask.CostomAttribute;
using TXTD.Admin.ScheduledTask.Jobs.Test;
using TXTD.Admin.ScheduledTask.Listeners;

namespace TXTD.Admin.ScheduledTask
{
    /// <summary>
    /// 定时任务调度服务
    /// </summary>
    public class ScheduledTaskService
    {
        private ISchedulerFactory schedulerFactory;
        //调度程序
        private static IScheduler scheduler = null;
        private ISysScheduledTaskService scheduledTaskService;
        private IJobListener jobListener;

        //缓存各个定时任务
        private static Dictionary<string, IJobDetail> JobDictionary = new();
        //缓存各个定时任务的触发器
        private static Dictionary<string, CronTriggerImpl> TriggerDictionary = new();

        private string groupName = "group1";
        public ScheduledTaskService(ISchedulerFactory _schedulerFactory, ISysScheduledTaskService _scheduledTaskService, IJobListener _jobListener)
        {
            this.schedulerFactory = _schedulerFactory;
            this.scheduledTaskService = _scheduledTaskService;
            this.jobListener = _jobListener;
        }
        /// <summary>
        /// 初始化
        /// </summary>
        /// <returns></returns>
        public virtual async Task Init()
        {
            scheduler = await schedulerFactory.GetScheduler();
            //获取所有实现了IJob的类
            var jobs = typeof(ScheduledTaskService).Assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IJob))).ToArray();

            foreach (var jobType in jobs)
            {
                var schedulerJobAttributes = jobType.GetCustomAttributes(typeof(SchedulerJobAttribute), true);
                if (schedulerJobAttributes != null && schedulerJobAttributes.Length > 0)
                {
                    //指定具体的任务job
                    var job = JobBuilder.Create(jobType).WithIdentity($"{jobType.FullName}ExtractJob", groupName).Build();

                    string JobKeyName = job.Key.Name;

                    SysScheduledTask sysScheduledTask = scheduledTaskService.GetScheduledTaskByJobKeyName(JobKeyName);
                    if (sysScheduledTask == null)
                    {
                        SchedulerJobAttribute schedulerJob = schedulerJobAttributes[0] as SchedulerJobAttribute;
                        sysScheduledTask = new SysScheduledTask()
                        {
                            JobKeyName = JobKeyName,
                            TaskName = schedulerJob.TaskName,
                            CronExpression = schedulerJob.CronExpression,
                            TaskDescribe = schedulerJob.TaskDescribe,
                            CreatedBy = "系统定时任务",
                            Enabled = true
                        };
                        scheduledTaskService.Add(sysScheduledTask);
                    }

                    //触发器
                    CronTriggerImpl trigger = (CronTriggerImpl)TriggerBuilder.Create().WithIdentity($"{JobKeyName}Trigger", groupName).StartAt(DateTime.UtcNow).WithCronSchedule(sysScheduledTask.CronExpression).Build();

                    //是否启用
                    if (sysScheduledTask.Enabled)
                    {
                        await scheduler.ScheduleJob(job, trigger);
                    }
                    //缓存Job
                    JobDictionary.Add(JobKeyName, job);
                    //缓存触发器
                    TriggerDictionary.Add(JobKeyName, trigger);
                }
            }

            //job监听
            scheduler.ListenerManager.AddJobListener(jobListener);

            //开始
            await scheduler.Start();
        }

        /// <summary>
        /// 修改任务
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<int> UpdateTask(SysScheduledTask model)
        {
            //验证Cron表达式是否正确
            if (CronExpression.IsValidExpression(model.CronExpression))
            {
                var job = JobDictionary[model.JobKeyName];
                var trigger = TriggerDictionary[model.JobKeyName];
                //删除job
                await scheduler.DeleteJob(JobDictionary[model.JobKeyName].Key);
                if (model.Enabled)
                {
                    //修改Cron表达式
                    trigger.CronExpressionString = model.CronExpression;
                    await scheduler.ScheduleJob(job, trigger);

                    //立即执行一次
                    await scheduler.TriggerJob(JobDictionary[model.JobKeyName].Key);
                }
            }
            else
            {
                throw new BusinessMessageException("Cron表达式错误，请更正");
            }
            return scheduledTaskService.Update(model);
        }

        /// <summary>
        /// 修改任务是否启用状态
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<int> UpdateTaskEnabled(SysScheduledTask model)
        {
            var job = JobDictionary[model.JobKeyName];
            var trigger = TriggerDictionary[model.JobKeyName];
            if (model.Enabled)
            {
                await scheduler.ScheduleJob(job, trigger);
            }
            else
            {
                await scheduler.DeleteJob(job.Key);
            }
            return scheduledTaskService.UpdateEnabled(model);
        }

        /// <summary>
        /// 立即执行
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<int> ExecuteNow(SysScheduledTask model)
        {
            var job = JobDictionary[model.JobKeyName];
            var trigger = TriggerDictionary[model.JobKeyName];
            if (model.Enabled)
            {
                await scheduler.TriggerJob(JobDictionary[model.JobKeyName].Key);
                Thread.Sleep(1000 * 5);
            }
            else
            {
                await scheduler.ScheduleJob(job, trigger);
                await scheduler.TriggerJob(JobDictionary[model.JobKeyName].Key);
                Thread.Sleep(1000 * 5);
                await scheduler.DeleteJob(job.Key);
            }
            return 1;
        }
    }
}